﻿using System;
using Oxage.Midi;
using Oxage.Common;

namespace Oxage.Midi
{
	public class MidiFilter : IFilter
	{
		#region Members
		private IConnector port1;
		private IConnector port2;
		#endregion

		#region Constructors
		public MidiFilter()
		{
		}

		public MidiFilter(IConnector port1, IConnector port2) : this()
		{
			this.Port1 = port1;
			this.Port2 = port2;
		}
		#endregion

		#region Properties
		public int OctaveShift
		{
			get;
			set;
		}
		#endregion

		#region Event handlers
		protected void Port1_Received(object sender, EventArgs<IMessage> e)
		{
			if (this.Port2 != null)
			{
				if (e.Result is MidiMessage)
				{
					//Octave shift
					(e.Result as MidiMessage).Note += (byte)(this.OctaveShift * 13);
				}
				this.Port2.Send(e.Result);
			}
		}

		protected void Port2_Received(object sender, EventArgs<IMessage> e)
		{
			if (this.Port1 != null)
			{
				if (e.Result is MidiMessage)
				{
					//Octave shift
					(e.Result as MidiMessage).Note += (byte)(this.OctaveShift * 13);
				}
				this.Port1.Send(e.Result);
			}
		}
		#endregion

		#region IFilter Members
		public IConnector Port1
		{
			get
			{
				return this.port1;
			}
			set
			{
				if (this.port1 != value)
				{
					//Close previous instance
					if (this.port1 != null)
					{
						this.port1.Received -= new EventHandler<EventArgs<IMessage>>(Port1_Received);
						this.port1.Close();
					}

					//Set the new instance
					this.port1 = value;
					if (this.port1 != null)
					{
						this.port1.Received += new EventHandler<EventArgs<IMessage>>(Port1_Received);
					}
				}
			}
		}

		public IConnector Port2
		{
			get
			{
				return this.port2;
			}
			set
			{
				if (this.port2 != value)
				{
					//Close previous instance
					if (this.port2 != null)
					{
						this.port2.Received -= new EventHandler<EventArgs<IMessage>>(Port2_Received);
						this.port2.Close();
					}

					//Set the new instance
					this.port2 = value;
					if (this.port2 != null)
					{
						this.port2.Received += new EventHandler<EventArgs<IMessage>>(Port2_Received);
					}
				}
			}
		}

		public bool Open()
		{
			bool completed = false;

			Close();
			if (this.Port1 != null && this.Port2 != null)
			{
				try
				{
					this.Port1.Open();
				}
				catch (Exception ex)
				{
					Close();
					throw new Exception("Port1: " + ex.Message, ex);
				}

				try
				{
					this.Port2.Open();
				}
				catch (Exception ex)
				{
					Close();
					throw new Exception("Port2: " + ex.Message, ex);
				}

				completed = true;
			}

			return completed;
		}

		public void Close()
		{
			try
			{
				if (this.Port1 != null)
				{
					this.Port1.Close();
				}
			}
			catch
			{
			}

			try
			{
				if (this.Port2 != null)
				{
					this.Port2.Close();
				}
			}
			catch
			{
			}
		}
		#endregion
	}
}
